home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 429_01 / chess12 / chess.cpp < prev    next >
C/C++ Source or Header  |  1994-04-29  |  28KB  |  1,252 lines

  1. #include "misc.hpp"
  2. #include "brdsize.hpp"
  3. #include "chess.hpp"
  4.  
  5. extern void OutOfMemory(void);
  6.  
  7. // piece values.
  8. const int VALUEKING = 0,
  9.       VALUEPAWN = 2,
  10.       VALUEROOK = 10,
  11.       VALUEKNIGHT = 6,
  12.       VALUEBISHOP = 6,
  13.       VALUEQUEEN = 18;
  14.  
  15. class PAWN : public PIECE
  16.   {
  17.   private:
  18.     // pointer to piece to which pawn has been promoted.  null if
  19.     // pawn has not been promoted.
  20.     PIECE *promotePiece;
  21.  
  22.   public:
  23.     PAWN(PIECECOLOR c) : PIECE(c, TYPEPAWN, VALUEPAWN), promotePiece(0) { }
  24.     virtual ~PAWN(void) { if (promotePiece) delete promotePiece; }
  25.  
  26.     void promote(PIECETYPE promoteType);
  27.     void restoreToPawn(void);
  28.  
  29.     virtual PIECETYPE whatType(void) const
  30.       {
  31.     if (promotePiece)
  32.       return(promotePiece->whatType());
  33.     else
  34.       return(PIECE::whatType());
  35.       }
  36.  
  37.     virtual int whatValue(void) const
  38.       {
  39.     if (promotePiece)
  40.       return(promotePiece->whatValue());
  41.     else
  42.       return(PIECE::whatValue());
  43.       }
  44.  
  45.     virtual void legalMoves
  46.       (
  47.     POSITION start,
  48.     const BOARD &board,
  49.         POSITIONLIST &moves
  50.       ) const;
  51.  
  52.   };
  53.  
  54. class ROOK : public PIECE
  55.   {
  56.   public:
  57.     ROOK(PIECECOLOR c) : PIECE(c, TYPEROOK, VALUEROOK)  { }
  58.  
  59.     virtual void legalMoves
  60.       (
  61.     POSITION start,
  62.     const BOARD &board,
  63.         POSITIONLIST &moves
  64.       ) const;
  65.  
  66.   };
  67.  
  68. class KNIGHT : public PIECE
  69.   {
  70.   public:
  71.     KNIGHT(PIECECOLOR c) : PIECE(c, TYPEKNIGHT, VALUEKNIGHT)  { }
  72.  
  73.     virtual void legalMoves
  74.       (
  75.     POSITION start,
  76.     const BOARD &board,
  77.         POSITIONLIST &moves
  78.       ) const;
  79.  
  80.   };
  81.  
  82. class BISHOP : public PIECE
  83.   {
  84.   public:
  85.     BISHOP(PIECECOLOR c) : PIECE(c, TYPEBISHOP, VALUEBISHOP)  { }
  86.  
  87.     virtual void legalMoves
  88.       (
  89.     POSITION start,
  90.     const BOARD &board,
  91.         POSITIONLIST &moves
  92.       ) const;
  93.  
  94.   };
  95.  
  96. class QUEEN : public PIECE
  97.   {
  98.   public:
  99.     QUEEN(PIECECOLOR c) : PIECE(c, TYPEQUEEN, VALUEQUEEN)  { }
  100.  
  101.     virtual void legalMoves
  102.       (
  103.     POSITION start,
  104.     const BOARD &board,
  105.         POSITIONLIST &moves
  106.       ) const;
  107.  
  108.   };
  109.  
  110. class KING : public PIECE
  111.   {
  112.   public:
  113.     KING(PIECECOLOR c) : PIECE(c, TYPEKING, VALUEKING)  { }
  114.  
  115.     virtual void legalMoves
  116.       (
  117.     POSITION start,
  118.     const BOARD &board,
  119.         POSITIONLIST &moves
  120.       ) const;
  121.  
  122.   };
  123.  
  124. // put all the pieces for one color at their starting positions on
  125. // the board
  126. LOCAL void setupPieces
  127.   (
  128.     PIECE *board[][NUMCOLS],
  129.     PIECECOLOR color,
  130.     // column in which the non-pawn pieces go
  131.     int backCol,
  132.     // column in which the pawns go
  133.     int pawnCol
  134.   )
  135.   {
  136.     BOOL f = TRUE;
  137.     int row;
  138.  
  139.     #define NEWPIECE(P, ROWOFFSET, COLOFFSET) \
  140.       f = f && \
  141.           ((board[ROWOFFSET][COLOFFSET] = new P) != (PIECE *) 0);
  142.  
  143.     NEWPIECE(ROOK(color), 0, backCol);
  144.     NEWPIECE(KNIGHT(color), 1, backCol);
  145.     NEWPIECE(BISHOP(color), 2, backCol);
  146.     NEWPIECE(QUEEN(color), 3, backCol);
  147.     NEWPIECE(KING(color), 4, backCol);
  148.     NEWPIECE(BISHOP(color), 5, backCol);
  149.     NEWPIECE(KNIGHT(color), 6, backCol);
  150.     NEWPIECE(ROOK(color), 7, backCol);
  151.  
  152.     for (row = 0; row < NUMROWS; row++)
  153.       NEWPIECE(PAWN(color), row, pawnCol);
  154.  
  155.     if (!f)
  156.       OutOfMemory();
  157.  
  158.     return;
  159.  
  160.     #undef NEWPIECE
  161.   }
  162.  
  163. BOARD::BOARD(void)
  164.   {
  165.     int row, col;
  166.  
  167.     for (row = 0; row < NUMROWS; row++)
  168.       for (col = 0; col < NUMCOLS; col++)
  169.     brd[row][col] = (PIECE *) 0;
  170.  
  171.     setupPieces(brd, WHITE, 0, 1);
  172.     setupPieces(brd, BLACK, 7, 6);
  173.  
  174.     wasLastMoveDoublePawn = FALSE;
  175.  
  176.     return;
  177.   }
  178.  
  179. BOARD::~BOARD(void)
  180.   {
  181.     int r, c;
  182.  
  183.     for (r = 0; r < NUMROWS; r++)
  184.       for (c = 0; c < NUMROWS; c++)
  185.     {
  186.       if (brd[r][c])
  187.         delete brd[r][c];
  188.     }
  189.  
  190.     return;
  191.   }
  192.  
  193. void BOARD::doMove
  194.   (
  195.     POSITION start,
  196.     POSITION end,
  197.     MOVEUNDODATA &undoData
  198.   )
  199.   {
  200.     undoData.capturedPiece = brd[end.row][end.col];
  201.     undoData.enPassantEffect = OTHERMOVE;
  202.  
  203.     brd[end.row][end.col] = brd[start.row][start.col];
  204.   
  205.     brd[start.row][start.col] = (PIECE *) 0;
  206.     brd[end.row][end.col]->moveDone();
  207.  
  208.     if (brd[end.row][end.col]->whatType() == TYPEPAWN)
  209.       {
  210.     if (wasLastMoveDoublePawn)
  211.       if ((doubleMovedPawn.row == end.row) &&
  212.           (doubleMovedPawn.col == start.col) &&
  213.           (start.row != end.row) &&
  214.           !undoData.capturedPiece)
  215.           // these last two tests are necessary to handle situations
  216.           // where the same color is moved twice in a row when
  217.           // looking for check in "canCastle" and looking for
  218.           // stalemate
  219.         {
  220.           // en passant capture
  221.           undoData.capturedPiece =
  222.         brd[doubleMovedPawn.row][doubleMovedPawn.col];
  223.           brd[doubleMovedPawn.row][doubleMovedPawn.col] =
  224.         (PIECE *) 0;
  225.           undoData.saveDoubleMoved = doubleMovedPawn;
  226.           undoData.enPassantEffect = ENPASSANTCAPTURE;
  227.           wasLastMoveDoublePawn = FALSE;
  228.           return;
  229.         }
  230.     {
  231.       int diff = start.col - end.col;
  232.       if (diff < 0)
  233.         diff = -diff;
  234.       if (diff == 2)
  235.         {
  236.           if (wasLastMoveDoublePawn)
  237.         {
  238.           undoData.saveDoubleMoved = doubleMovedPawn;
  239.           undoData.enPassantEffect = AFTERDOUBLEMOVE;
  240.         }
  241.           doubleMovedPawn = end;
  242.           wasLastMoveDoublePawn = TRUE;
  243.           return;
  244.         }
  245.     }
  246.       }
  247.  
  248.     if (wasLastMoveDoublePawn)
  249.       {
  250.     undoData.saveDoubleMoved = doubleMovedPawn;
  251.     undoData.enPassantEffect = AFTERDOUBLEMOVE;
  252.       }
  253.     wasLastMoveDoublePawn = FALSE;
  254.  
  255.     return;
  256.   }
  257.  
  258. void BOARD::undoMove
  259.   (
  260.     POSITION end,
  261.     POSITION orig,
  262.     MOVEUNDODATA undoData
  263.   )
  264.   {
  265.     brd[orig.row][orig.col] = brd[end.row][end.col];
  266.  
  267.     brd[orig.row][orig.col]->moveUndone();
  268.  
  269.     if (undoData.enPassantEffect == ENPASSANTCAPTURE)
  270.       {
  271.     brd[end.row][orig.col] = undoData.capturedPiece;
  272.     brd[end.row][end.col] = (PIECE *) 0;
  273.       }
  274.     else
  275.       brd[end.row][end.col] = undoData.capturedPiece;
  276.  
  277.     if (undoData.enPassantEffect == OTHERMOVE)
  278.       wasLastMoveDoublePawn = FALSE;
  279.     else
  280.       {
  281.     wasLastMoveDoublePawn = TRUE;
  282.     doubleMovedPawn = undoData.saveDoubleMoved;
  283.       }
  284.  
  285.     return;
  286.   }
  287.  
  288. BOOL BOARD::canCastle(MOVETYPE whichCastle, PIECECOLOR color)
  289.   {
  290.     int col = color == WHITE ? 0 : 7;
  291.     int row, rowStep;
  292.     BOARDMETRIC metric;
  293.  
  294.     if (whichCastle == QUEENSIDECASTLE)
  295.       {
  296.     row = 0;
  297.     rowStep = 1;
  298.       }
  299.     else
  300.       {
  301.     row = 7;
  302.     rowStep = -1;
  303.       }
  304.  
  305.     // make sure king & rook in initial positions and have never been
  306.     // moved.
  307.     if (!brd[row][col])
  308.       return(FALSE);
  309.     if (brd[row][col]->hasBeenMoved())
  310.       return(FALSE);
  311.     if (!brd[4][col])
  312.       return(FALSE);
  313.     if (brd[4][col]->hasBeenMoved())
  314.       return(FALSE);
  315.  
  316.     // make sure no pieces in between
  317.     for ( ; ; )
  318.       {
  319.     row += rowStep;
  320.     if (row == 4)
  321.       break;
  322.     if (brd[row][col])
  323.       return(FALSE);
  324.       }
  325.  
  326.     // make sure king is not in check
  327.     findBestMoves(1, OtherColor(color), metric, (BESTMOVES *) 0);
  328.     if (metric.kingSituation[color] == KINGLOST)
  329.       return(FALSE);
  330.  
  331.     // make sure king would not be in check in intermediate position
  332.     brd[4 - rowStep][col] = brd[4][col];
  333.     brd[4][col] = (PIECE *) 0;
  334.     findBestMoves(1, OtherColor(color), metric, (BESTMOVES *) 0);
  335.     brd[4][col] = brd[4 - rowStep][col];
  336.     brd[4 - rowStep][col] = (PIECE *) 0;
  337.  
  338.     return(metric.kingSituation[color] == KINGOK);
  339.   }
  340.  
  341. void BOARD::castle
  342.   (
  343.     MOVETYPE whichCastle,
  344.     PIECECOLOR color,
  345.     MOVEUNDODATA &undoData
  346.   )
  347.   {
  348.     int col = color == WHITE ? 0 : 7;
  349.  
  350.     if (whichCastle == QUEENSIDECASTLE)
  351.       {
  352.     brd[3][col] = brd[0][col];
  353.     brd[2][col] = brd[4][col];
  354.     brd[0][col] = (PIECE *) 0;
  355.     brd[4][col] = (PIECE *) 0;
  356.     brd[3][col]->moveDone();
  357.     brd[2][col]->moveDone();
  358.       }
  359.     else
  360.       {
  361.     brd[5][col] = brd[7][col];
  362.     brd[6][col] = brd[4][col];
  363.     brd[7][col] = (PIECE *) 0;
  364.     brd[4][col] = (PIECE *) 0;
  365.     brd[5][col]->moveDone();
  366.     brd[6][col]->moveDone();
  367.       }
  368.  
  369.     if (wasLastMoveDoublePawn)
  370.       {
  371.     undoData.enPassantEffect = AFTERDOUBLEMOVE;
  372.     undoData.saveDoubleMoved = doubleMovedPawn;
  373.     wasLastMoveDoublePawn = FALSE;
  374.